package cn.yuyiling.jelly.kgai.service.impl;

import cn.yuyiling.jelly.kg.api.KnowledgePointService;
import cn.yuyiling.jelly.kg.mongodb.entity.KnowledgePoint;
import cn.yuyiling.jelly.kgai.api.KnowledgeAIService;
import cn.yuyiling.jelly.kgai.config.LLMConfigManager;
import cn.yuyiling.jelly.qa.api.AnswerService;
import cn.yuyiling.jelly.qa.api.QuestionService;
import cn.yuyiling.jelly.qa.mongodb.entity.Answer;
import cn.yuyiling.jelly.qa.mongodb.entity.Question;

import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.model.ChatModel;


import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

@DubboService
public class KnowledgeAIServiceImpl implements KnowledgeAIService {
    private static final Logger logger = LoggerFactory.getLogger(KnowledgeAIServiceImpl.class);
    private final ChatClient chatClient;

    @DubboReference
    private KnowledgePointService knowledgePointService;
    @DubboReference
    private QuestionService questionService;
    @DubboReference
    private AnswerService answerService;

    public KnowledgeAIServiceImpl(ChatModel chatModel) {
        logger.info("KgAiConfig init");
        LLMConfigManager configManager = new LLMConfigManager();
        String model = configManager.getModel();
        String token = configManager.getToken();
        int timeout = configManager.getTimeout();
        String defaultSystem = configManager.getDefaultSystem();
        logger.info("KgAiConfig init {}", model);
        logger.info("KgAiConfig init {}", token);
        logger.info("KgAiConfig init {}", timeout);
        logger.info("KgAiConfig init {}", defaultSystem);
        this.chatClient = ChatClient.builder(chatModel)
                // 实现 Logger 的 Advisor
                .defaultAdvisors(
                        new SimpleLoggerAdvisor()
                )
                // 设置 ChatClient 中 ChatModel 的 Options 参数
                .defaultOptions(
                        DashScopeChatOptions.builder()
                                .withModel(model)
                                .build()
                )
                .defaultSystem(defaultSystem)
                .build();

    }

    @Override
    public KnowledgePoint fillKnowledgePoint(KnowledgePoint knowledgePoint) {
        // 构造提示词模板
        String promptTemplate = """
                你是一位资深技术专家，请用中文为技术学习者生成结构化学习内容。
                要求：
                1. 以Markdown格式组织内容
                2. 必须包含以下模块：
                   - 核心概念
                   - 工作原理
                   - 应用场景（列表形式）
                   - 示例代码
                3. 用通俗易懂的语言解释技术难点
                
                需要解释的技术名称：%s
                """;

        // 调用大模型生成内容
        String generatedContent = this.chatClient.prompt()
                .user(String.format(promptTemplate, knowledgePoint.getName()))
                .call()
                .content();

        //查询是否已经存在知识点，如果有就更新否则插入
        KnowledgePoint existingKnowledgePoint =knowledgePointService.getKnowledgePointByName(knowledgePoint.getName());
        if (existingKnowledgePoint != null) {
            // 更新已有知识点
            existingKnowledgePoint.setContent(validateMarkdown(generatedContent));
            logger.info("fill existing knowledge point: {}", existingKnowledgePoint);
            return knowledgePointService.updateKnowledgePoint(existingKnowledgePoint.getId(), existingKnowledgePoint);
        } else {
            // 创建新知识点
            knowledgePoint.setName(knowledgePoint.getName());
            knowledgePoint.setContent(validateMarkdown(generatedContent));
            logger.info("fill and create knowledge point: {}", knowledgePoint);
            return knowledgePointService.createKnowledgePoint(knowledgePoint);
        }
    }

    private String validateMarkdown(String content) {
        if (content == null) {
            return "";
        }
        return content.replace("```markdown", "").trim();
    }

    @Override
    public Question extractKnowledgePoint(Question question) {
        String prompt = """
                请从以下问题内容中提取涉及的知识点，并以如下格式输出：
                知识点名称：xxx
                知识点名称：xxxxx
                ...
                要求：
                - 每个知识点单独一行，使用“知识点名称：”前缀。
                - 不添加额外说明或格式。
                - 知识点应为简洁的名词或短语。
                问题: %s
                """;

        String response = this.chatClient.prompt()
                .user(String.format(prompt, question.getContent().getText()))
                .call()
                .content();

        List<String> extractedKnowledgePoint = new ArrayList<>();
        for (String line : response.split("\n")) {
            if (line.startsWith("知识点名称：")) {
                String kp = line.replaceFirst("知识点名称：", "").trim();
                if (!kp.isEmpty()) {
                    extractedKnowledgePoint.add(kp);

                }
            }
        }

        Question existedQuestion = questionService.getQuestionById(question.getId());
        if (existedQuestion == null) {
            logger.warn("Question with ID {} not found.", question.getId());
            return null;
        }
        if (extractedKnowledgePoint != null && !extractedKnowledgePoint.isEmpty()) {
            existedQuestion.setKnowledgePoints(extractedKnowledgePoint);
            logger.info("Extracted knowledge points to question with ID: {}, knowledgePoints: {}", question.getId(), extractedKnowledgePoint);
        }

        return questionService.updateQuestion(existedQuestion.getId(), existedQuestion);
    }

    @Override
    public Question evaluateDifficultyOfQuestion(Question question) {
        String prompt = """
            请判断以下问题的难度等级（只能选择：简单、中等、困难）。
            要求：
            - 只需输出简单、中等或困难（例如：中等）。
            - 不要添加任何解释、文字或格式。
            问题: %s
            """;

        String response = this.chatClient.prompt()
                .user(String.format(prompt, question.getContent().getText()))
                .call()
                .content();

        Question existedQuestion = questionService.getQuestionById(question.getId());
        if (existedQuestion == null) {
            logger.warn("Question with ID {} not found.", question.getId());
            return null;
        }

        Question.Metadata metadata = existedQuestion.getMetadata();
        if (metadata == null) {
            metadata = new Question.Metadata();
            existedQuestion.setMetadata(metadata);
        }

        metadata.setAiEvaluation(response);
        logger.info("evaluating question with ID: {}", existedQuestion.getId());
        return questionService.updateQuestion(existedQuestion.getId(), existedQuestion);
    }

    @Override
    public Answer evaluateAnswer(Answer answer) {
        String prompt = """
            根据以下问题，请对以下用户回答的正确度进行评分（满分100分）。
            要求：
            - 只需输出一个表示分数的整数（例如：85）。
            - 不要添加任何解释、文字或格式。
            问题：%s
            用户回答: %s
            """;

        String response = "";
        Question existedQuestion = questionService.getQuestionById(answer.getParentId());

        if (existedQuestion != null) {
            response = this.chatClient.prompt()
                    .user(String.format(prompt, existedQuestion.getContent().getText(), answer.getContent().getText()))
                    .call()
                    .content();
        }else{
            response = this.chatClient.prompt()
                    .user(String.format(prompt, " ", answer.getContent().getText()))
                    .call()
                    .content();
        }

        Answer existedAnswer = answerService.getAnswerById(answer.getId());
        if (existedAnswer == null) {
            logger.warn("Answer with ID {} not found.", answer.getId());
            return null;
        }

        Answer.Metadata metadata = existedAnswer.getMetadata();
        if (metadata == null) {
            metadata = new Answer.Metadata();
            existedAnswer.setMetadata(metadata);
        }

        metadata.setAiEvaluation(Integer.parseInt(response.trim()));
        logger.info("evaluating answer with ID: {}", existedAnswer.getId());
        return answerService.updateAnswer(existedAnswer.getId(), existedAnswer);
    }



}
